home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
OREF.C
< prev
next >
Wrap
Text File
|
1990-03-02
|
16KB
|
577 lines
/*
* File: oref.c
* Contents: bang, random, sect, subsc
*/
#include "::h:config.h"
#include "::h:rt.h"
#include "rproto.h"
#ifdef PreProcess
/* include(../M4/ops.m4) /* */
/* */
#endif /* PreProcess */
/*
* !x - generate successive values from object x.
*/
OpDcl(bang,1,"!")
{
register word i, j, slen, rlen;
register union block *bp;
register dptr dp;
register char *sp;
int typ1;
char sbuf[MaxCvtLen];
FILE *fd;
Arg2 = Arg1;
if (DeRef(Arg1) == Error)
RunErr(0, NULL);
if ((typ1 = cvstr(&Arg1, sbuf)) != CvtFail) {
/*
* A string is being banged.
*/
i = 1;
while (i <= StrLen(Arg1)) {
/*
* Loop through the string using i as an index.
*/
if (typ1 == Cvt) {
/*
* Arg1 was converted to a string, thus, the resulting string
* cannot be modified and a trapped variable is not needed.
* Make a one-character string out of the next character
* in Arg1 and suspend it.
*/
if (strreq((word)1) == Error)
RunErr(0, NULL);
StrLen(Arg0) = 1;
StrLoc(Arg0) = alcstr(StrLoc(Arg1)+i-1, (word)1);
Suspend;
}
else {
/*
* Arg1 is a string and thus a trapped variable must be made
* for the one character string being suspended.
*/
if (blkreq((word)sizeof(struct b_tvsubs)) == Error)
RunErr(0, NULL);
mksubs(&Arg2, &Arg1, i, (word)1, &Arg0);
Suspend;
Arg1 = Arg2;
if (DeRef(Arg1) == Error)
RunErr(0, NULL);
if (!Qual(Arg1))
RunErr(103, &Arg1);
}
i++;
}
}
else {
/*
* Arg1 is not a string.
*/
switch (Type(Arg1)) {
case T_List:
/*
* Arg1 is a list. Chain through each list element block and for
* each one, suspend with a variable pointing to each
* element contained in the block.
*/
bp = BlkLoc(Arg1);
for (bp = bp->list.listhead; bp != NULL; bp = bp->lelem.listnext) {
for (i = 0; i < bp->lelem.nused; i++) {
j = bp->lelem.first + i;
if (j >= bp->lelem.nslots)
j -= bp->lelem.nslots;
dp = &bp->lelem.lslots[j];
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
BlkLoc(Arg1) = bp; /* save in Arg1 since bp is untended */
Suspend;
bp = BlkLoc(Arg1); /* bp is untended, must reset */
}
}
break;
case T_File:
/*
* Arg1 is a file. Read the next line into the string space
* and suspend the newly allocated string.
*/
fd = BlkLoc(Arg1)->file.fd;
if ((BlkLoc(Arg1)->file.status & Fs_Read) == 0)
RunErr(212, &Arg1);
for (;;) {
StrLen(Arg0) = 0;
do {
if ((slen = getstrg(sbuf,MaxCvtLen,fd)) == -1)
Fail;
rlen = slen < 0 ? (word)MaxCvtLen : slen;
if (strreq(rlen) == Error)
RunErr(0, NULL);
sp = alcstr(sbuf,rlen);
if (StrLen(Arg0) == 0)
StrLoc(Arg0) = sp;
StrLen(Arg0) += rlen;
} while (slen < 0);
Suspend;
}
break;
case T_Table:
/*
* Arg1 is a table. Generate the element values.
*/
MakeInt(2, &Arg2); /* indicate that we want the values */
Forward(hgener); /* go to the hash generator */
case T_Set:
/*
* Arg1 is a set. Generate the element values.
*/
MakeInt(0, &Arg2); /* indicate that we want set elements */
Forward(hgener); /* go to the hash generator */
case T_Record:
/*
* Arg1 is a record. Loop through the fields and suspend
* a variable pointing to each one.
*/
bp = BlkLoc(Arg1);
j = bp->record.recdesc->proc.nfields;
for (i = 0; i < j; i++) {
dp = &bp->record.fields[i];
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
Suspend;
bp = BlkLoc(Arg1); /* bp is untended, must reset */
}
break;
default: /* This object can not be compromised. */
RunErr(116, &Arg1);
}
}
/*
* Eventually fail.
*/
Fail;
}
#define RandVal (RanScale*(k_random=(RandA*k_random+RandC)&MaxLong))
/*
* ?x - produce a randomly selected element of x.
*/
OpDcl(random,1,"?")
{
register word val, i, j, n;
register union block *bp, *ep;
struct b_slots *seg;
char sbuf[MaxCvtLen];
dptr dp;
double rval;
Arg2 = Arg1;
if (DeRef(Arg1) == Error)
RunErr(0, NULL);
if (Qual(Arg1)) {
/*
* Arg1 is a string, produce a random character in it as the result.
* Note that a substring trapped variable is returned.
*/
if ((val = StrLen(Arg1)) <= 0)
Fail;
if (blkreq((word)sizeof(struct b_tvsubs)) == Error)
RunErr(0, NULL);
rval = RandVal; /* This form is used to get around */
rval *= val; /* a bug in a certain C compiler */
mksubs(&Arg2, &Arg1, (word)rval + 1, (word)1, &Arg0);
Return;
}
switch (Type(Arg1)) {
case T_Cset:
/*
* Arg1 is a cset. Convert it to a string, select a random character
* of that string and return it. Note that a substring trapped
* variable is not needed.
*/
cvstr(&Arg1, sbuf);
if ((val = StrLen(Arg1)) <= 0)
Fail;
if (strreq((word)1) == Error)
RunErr(0, NULL);
StrLen(Arg0) = 1;
rval = RandVal;
rval *= val;
StrLoc(Arg0) = alcstr(StrLoc(Arg1)+(word)rval, (word)1);
Return;
case T_List:
/*
* Arg1 is a list. Set i to a random number in the range [1,*Arg1],
* failing if the list is empty.
*/
bp = BlkLoc(Arg1);
val = bp->list.size;
if (val <= 0)
Fail;
rval = RandVal;
rval *= val;
i = (word)rval + 1;
j = 1;
/*
* Work down chain list of list blocks and find the block that
* contains the selected element.
*/
bp = bp->list.listhead;
while (i >= j + bp->lelem.nused) {
j += bp->lelem.nused;
bp = bp->lelem.listnext;
if (bp == NULL)
syserr("list reference out of bounds in random");
}
/*
* Locate the appropriate element and return a variable
* that points to it.
*/
i += bp->lelem.first - j;
if (i >= bp->lelem.nslots)
i -= bp->lelem.nslots;
dp = &bp->lelem.lslots[i];
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
Return;
case T_Table:
case T_Set:
/*
* Arg1 is a table or a set. Set n to a random number in the range
* [1,*Arg1], failing if the structure is empty.
*/
bp = BlkLoc(Arg1);
val = bp->table.size;
if (val <= 0)
Fail;
rval = RandVal;
rval *= val;
n = (word)rval + 1;
/*
* Walk down the hash chains to find and return the n'th element.
*/
for (i = 0; i < HSegs && (seg = bp->table.hdir[i]) != NULL; i++)
for (j = segsize[i] - 1; j >= 0; j--)
for (ep = seg->hslots[j]; ep != NULL; ep = ep->telem.clink)
if (--n <= 0) {
if (Type(Arg1) == T_Set) {
/*
* For a set, return the element value.
*/
Arg0 = ep->selem.setmem;
}
else {
/*
* For a table, return a variable pointing to the
* selected element.
*/
dp = &ep->telem.tval;
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
}
Return;
}
case T_Record:
/*
* Arg1 is a record. Set val to a random number in the range
* [1,*Arg1] (*Arg1 is the number of fields), failing if the
* record has no fields.
*/
bp = BlkLoc(Arg1);
val = bp->record.recdesc->proc.nfields;
if (val <= 0)
Fail;
/*
* Locate the selected element and return a variable
* that points to it
*/
rval = RandVal;
rval *= val;
dp = &bp->record.fields[(word)rval];
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
Return;
#ifdef LargeInts
case T_Bignum:
if (bigrand(&Arg1, &Arg0) == Error) /* alcbignum failed */
RunErr(0, NULL);
Return;
#endif /* LargeInts */
default:
/*
* Try converting it to an integer
*/
switch (cvint(&Arg1)) {
case T_Integer:
/*
* Arg1 is an integer, be sure that it's non-negative.
*/
val = (word)IntVal(Arg1);
if (val < 0)
RunErr(205, &Arg1);
/*
* val contains the integer value of Arg1. If val is 0, return
* a real in the range [0,1], else return an integer in the
* range [1,val].
*/
if (val == 0) {
rval = RandVal;
if (makereal(rval, &Arg0) == Error)
RunErr(0, NULL);
}
else {
rval = RandVal;
rval *= val;
MakeInt((long)rval + 1, &Arg0);
}
Return;
default:
/*
* Arg1 is of a type for which random generation is not supported
*/
RunErr(113, &Arg1);
}
}
}
/*
* x[i:j] - form a substring or list section of x.
*/
OpDcl(sect,3,"[:]")
{
register word i, j, t;
int typ1;
char sbuf[MaxCvtLen];
if (blkreq((word)sizeof(struct b_tvsubs)) == Error)
RunErr(0, NULL);
if (cvint(&Arg2) == CvtFail)
RunErr(101, &Arg2);
if (cvint(&Arg3) == CvtFail)
RunErr(101, &Arg3);
Arg4 = Arg1;
if (DeRef(Arg1) == Error)
RunErr(0, NULL);
if (Arg1.dword == D_List) {
i = cvpos(IntVal(Arg2), BlkLoc(Arg1)->list.size);
if (i == CvtFail)
Fail;
j = cvpos(IntVal(Arg3), BlkLoc(Arg1)->list.size);
if (j == CvtFail)
Fail;
if (i > j) {
t = i;
i = j;
j = t;
}
if (cplist(&Arg1, &Arg0, i, j) == Error)
RunErr(0, NULL);
Return;
}
if ((typ1 = cvstr(&Arg1, sbuf)) == CvtFail)
RunErr(110, &Arg1);
i = cvpos(IntVal(Arg2), StrLen(Arg1));
if (i == CvtFail)
Fail;
j = cvpos(IntVal(Arg3), StrLen(Arg1));
if (j == CvtFail)
Fail;
if (i > j) { /* convert section to substring */
t = i;
i = j;
j = t - j;
}
else
j = j - i;
if (typ1 == Cvt) {
/*
* A string was created - just return a string
*/
if (strreq(j) == Error)
RunErr(0, NULL);
StrLen(Arg0) = j;
StrLoc(Arg0) = alcstr(StrLoc(Arg1)+i-1, j);
}
else /* else make a substring tv */
mksubs(&Arg4, &Arg1, i, j, &Arg0);
Return;
}
/*
* x[y] - access yth character or element of x.
*/
OpDcl(subsc,2,"[]")
{
register word i, j;
register union block *bp;
register uword hn;
int typ1, res;
dptr dp;
union block **dp1;
char sbuf[MaxCvtLen];
/*
* Make a copy of Arg1.
*/
Arg3 = Arg1;
if (DeRef(Arg1) == Error)
RunErr(0, NULL);
if ((typ1 = cvstr(&Arg1, sbuf)) != CvtFail) {
/*
* Arg1 is a string, make sure that Arg2 is an integer.
*/
if (cvint(&Arg2) == CvtFail)
RunErr(101, &Arg2);
/*
* Convert Arg2 to a position in Arg1 and fail if the position is out
* of bounds.
*/
i = cvpos(IntVal(Arg2), StrLen(Arg1));
if (i == CvtFail || i > StrLen(Arg1))
Fail;
if (typ1 == Cvt) {
/*
* Arg1 was converted to a string, so it cannot be assigned back into.
* Just return a string containing the selected character.
*/
if (strreq((word)1) == Error)
RunErr(0, NULL);
StrLen(Arg0) = 1;
StrLoc(Arg0) = alcstr(StrLoc(Arg1)+i-1, (word)1);
}
else {
/*
* Arg1 is a string, make a substring trapped variable for the one
* character substring selected and return it.
*/
if (blkreq((word)sizeof(struct b_tvsubs)) == Error)
RunErr(0, NULL);
mksubs(&Arg3, &Arg1, i, (word)1, &Arg0);
}
Return;
}
/*
* Arg1 is not a string or convertible to one, see if it's an aggregate.
*/
switch (Type(Arg1)) {
case T_List:
/*
* Make sure that Arg2 is an integer and that the
* subscript is in range.
*/
if (cvint(&Arg2) == CvtFail)
RunErr(101, &Arg2);
i = cvpos(IntVal(Arg2), BlkLoc(Arg1)->list.size);
if (i == CvtFail || i > BlkLoc(Arg1)->list.size)
Fail;
/*
* Locate the list-element block containing the desired
* element.
*/
bp = BlkLoc(Arg1)->list.listhead;
j = 1;
while (bp != NULL && i >= j + bp->lelem.nused) {
j += bp->lelem.nused;
bp = bp->lelem.listnext;
}
/*
* Locate the desired element and return a pointer to it.
*/
i += bp->lelem.first - j;
if (i >= bp->lelem.nslots)
i -= bp->lelem.nslots;
dp = &bp->lelem.lslots[i];
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
Return;
case T_Table:
/*
* Arg1 is a table. Locate the appropriate bucket
* based on the hash value.
*/
if (blkreq((word)sizeof(struct b_tvtbl)) == Error)
RunErr(0, NULL);
hn = hash(&Arg2);
dp1 = memb(BlkLoc(Arg1), &Arg2, hn, &res);
if (res == 1) {
bp = *dp1;
dp = &bp->telem.tval;
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
}
else {
/*
* Arg1[Arg2] is not in the table, make a table element trapped
* variable and return it as the result.
*/
Arg0.dword = D_Tvtbl;
BlkLoc(Arg0) = (union block *)alctvtbl(&Arg1, &Arg2, hn);
}
Return;
case T_Record:
/*
* Arg1 is a record. Convert Arg2 to an integer and be sure that it
* it is in range as a field number.
*/
if (cvint(&Arg2) == CvtFail)
RunErr(101, &Arg2);
bp = BlkLoc(Arg1);
i = cvpos(IntVal(Arg2), (word)(bp->record.recdesc->proc.nfields));
if (i == CvtFail || i > bp->record.recdesc->proc.nfields)
Fail;
/*
* Locate the appropriate field and return a pointer to it.
*/
dp = &bp->record.fields[i-1];
Arg0.dword = D_Var + ((word *)dp - (word *)bp);
VarLoc(Arg0) = (dptr)bp;
Return;
default:
/*
* Arg1 is of a type that cannot be subscripted.
*/
RunErr(114, &Arg1);
}
}